fix: array field types persist + Field.time accepts time-of-day#2004
Merged
Conversation
Two field-type runtime gaps found driving the showcase field-zoo (which had
no seed data, so neither was ever exercised at runtime).
1. Array/object fields broke every write (driver-sql). multiselect/checkboxes/
tags/repeater/vector were missing from the SQL driver's JSON-field
classification, so their arrays reached the better-sqlite3 binder
un-serialized → "SQLite3 can only bind numbers, strings, bigints, buffers,
and null" 500 on insert/update (incl. task.labels on a normal object). The
DDL column-type switch and isJsonField had drifted into two lists; unified
into one JSON_COLUMN_TYPES source covering the array/object types, plus a
formatInput safety net that serializes any stray array/object so an
unclassified field degrades to a stored string instead of crashing.
2. Field.time rejected every valid value (objectql). The validator reused the
date/datetime Date.parse branch, which is NaN for any bare time string, so
`time` could never accept 14:30 / 09:05:30. Now validates HH:MM / HH:MM:SS
(optional fractional seconds + Z/offset), still accepts a full ISO datetime;
date/datetime unchanged. (Date.parse('14:60') returns a bogus number, so the
fallback requires a real date component — malformed times are rejected.)
Verified live on app-showcase: full field-zoo specimen now persists +
round-trips. Tests: driver-sql array round-trip (155 green) + time validator
(objectql 652 green).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 19 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
added a commit
that referenced
this pull request
Jun 17, 2026
…ook (#2005) The Field Zoo declared all 48 field types but shipped NO seed data, so no field type was ever exercised with a real value — which is exactly why the array-serialization and Field.time bugs (fixed in #2004) went unnoticed. - Seed two field-zoo specimens ("Full" + "Minimal") covering every input-able field type with real values: arrays (multiselect/checkboxes/tags/repeater/ vector), objects (composite/address/location/json/record), time (14:30 / 09:05:30), relational (lookup→Account, master_detail→Project by externalId), and computed (formula=315, autonumber). `f_secret` is intentionally omitted — the seed path has no CryptoProvider so a secret value is refused fail-closed. This doubles as a runtime regression guard: a field type that can't persist now fails the boot seed instead of shipping silently. - Guard the showcase_warn_over_budget hook condition with has() — a partial rollup update (task_count recompute) fires afterUpdate with a record lacking spent/budget, and CEL throws "No such key" on a bare record.spent. has() is the missing-key-safe macro; the noisy warning is gone. Verified live: both specimens seed (37 populated f_* fields on Full); coverage test 20 green; warn_over_budget "No such key" warnings = 0 after a task update. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 17, 2026
os-zhuang
added a commit
that referenced
this pull request
Jun 18, 2026
…thoring) (#2022) Extends the dogfood gate from "pin one example app" toward the platform's real risk: third parties have an AI author arbitrary metadata, so every authorable primitive needs a runtime proof — not a static shape check. `showcase_field_zoo` carries one field of (almost) every protocol FieldType but was only static-checked (the bundle registers it). This adds the first capability-matrix block: write one record covering many field types over the real REST data API, read it back, assert each round-trips with type fidelity. - Headliner coverage = the #2004 regressions: array-typed fields (multiselect/checkboxes/tags) and Field.time (time-of-day) — all proven to round-trip end-to-end on the in-memory (WASM) driver path `objectstack dev` uses for :memory:. - On first run it surfaced three real type-fidelity gaps — rating/slider/toggle persist but read back as strings ('4'/'25'/'1') while number/currency/percent/ boolean round-trip correctly. They are quarantined with `it.fails` (passes while broken, turns RED when fixed) rather than hidden by coercion, and filed as a separate task. Private package — no changeset. 21 passed + 3 expected-fail. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang
added a commit
that referenced
this pull request
Jun 25, 2026
fix(console): route org-less users into guided org creation on multi-org (#2004) objectui@9130b33ec35ac79bcd0da2618be4806e49ac2475
os-zhuang
added a commit
that referenced
this pull request
Jun 26, 2026
…ad (SQLite) (#2347) Field.time is a tz-naive time-of-day, not an instant (#2004). A defaultValue:'NOW()' time column historically took the full SQLite CURRENT_TIMESTAMP default, so a defaulted/legacy row read back a full 'YYYY-MM-DD HH:MM:SS' timestamp instead of a time-of-day. formatOutput now repairs a Field.time value to just its time portion (toTimeOnly): a legacy full timestamp (or a full ISO value that leaked into the column) is sliced to HH:MM[:SS[.fff]], while a value already stored as a bare time-of-day is left untouched. Deliberately NARROW + read-only (no write/filter counterpart) so it introduces no write/read asymmetry and preserves exact round-trips for bare time-of-day values (the field-zoo f_time guard). Runs for every dialect (a native TIME column already returns a time-of-day → no-op). Adds a timeFields registry + registration mirroring dateFields/datetimeFields. Completes the temporal read normalization alongside #2346: datetime -> ISO-8601-Z, date -> YYYY-MM-DD, time -> wall-clock time-of-day. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two field-type runtime gaps found driving
app-showcase's field-zoo end-to-end. The showcase's coverage test is green because it asserts every field type is declared — but field-zoo has no seed data, so no field type was ever exercised with a real value. Both bugs are pure "passes build / silent at runtime."1. Array/object field types broke every write (
driver-sql)multiselect/checkboxes/tags/repeater/vectorwere missing from the SQL driver's JSON-field classification. Their array values reached the better-sqlite3 binder un-serialized:This hit common field types on insert and update — even
task.labelson an ordinary object (labels: ['red','blue']→ 500). Root cause: the DDL column-type switch andisJsonFieldhad drifted into two separate type lists; the array types were in neither.Fix: one shared
JSON_COLUMN_TYPESsource used by both the DDL switch andisJsonField, now covering the array/object types (so the columns are created as JSON and round-trip as arrays/objects). Plus aformatInputsafety net that serializes any stray array/object value, so an unclassified field degrades to a stored string instead of a hard 500.2.
Field.timerejected every valid value (objectql)The validator reused the
date/datetimebranch (Date.parse), which isNaNfor any bare time string — so atimefield could never accept14:30or09:05:30.Fix:
timenow validates a time-of-day (HH:MM/HH:MM:SS, optional fractional seconds +Z/offset) and still accepts a full ISO datetime;date/datetimeunchanged. (Date.parse('14:60')returns a bogus number in Node, so the lenient fallback requires a real date component — malformed times like14:60/25:00are correctly rejected.)Verification
multiselect/tags/checkboxes/repeater/vectorcome back as arrays/objects,timeas14:30.task.labelsarray persists.sql-driver-array-fields.test.ts(round-trip + update + empty-array) →@objectstack/driver-sql155 green; time-validator cases (accept HH:MM/HH:MM:SS/ISO, reject malformed, no date/datetime regression) →@objectstack/objectql652 green.Follow-ups (separate, showcase-side)
showcase_warn_over_budgethook references a nonexistentrecord.spentfield (fires a "no such key" warning). (Next PR.)🤖 Generated with Claude Code